package com.medical.interrogation.service.impl;

import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.medical.interrogation.service.FastVoService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author websocket服务
 */
@ServerEndpoint(value = "/imserver/{patientId}")
@Component
public class PatientWebSocketServer {

    private static FastVoService fastVoService;

    @Autowired
    private void setFastVoService(FastVoService fastVoService) {
        PatientWebSocketServer.fastVoService = fastVoService;
    }

    private static final Logger log = LoggerFactory.getLogger(PatientWebSocketServer.class);
    public static final Map<String, Session> sessionMap = new ConcurrentHashMap<>();

    /**
     * WebSocket连接建立时调用
     * @param session WebSocket会话
     * @param patientId 患者ID，从路径参数中获取
     */
    @OnOpen
    public void onOpen(Session session, @PathParam("patientId") String patientId) {
        sessionMap.put(patientId, session);
        log.info("有新患者加入，patientId={}, 当前在线人数为：{}", patientId, sessionMap.size());
        // 构建在线患者列表并广播给所有客户端
        JSONObject result = new JSONObject();
        JSONArray array = new JSONArray();
        result.put("patients", array);
        for (Object key : sessionMap.keySet()) {
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("patientId", key);
            array.add(jsonObject);
        }
        sendAllMessage(JSONUtil.toJsonStr(result));  // 后台发送消息给所有的客户端
    }

    /**
     * WebSocket连接关闭时调用
     * @param session WebSocket会话
     * @param patientId 患者ID，从路径参数中获取
     */
    @OnClose
    public void onClose(Session session, @PathParam("patientId") String patientId) {
        sessionMap.remove(patientId);
        log.info("有一连接关闭，移除patientId={}的患者session, 当前在线人数为：{}", patientId, sessionMap.size());
    }

    /**
     * 接收客户端消息时调用
     * @param message 客户端发送的消息
     * @param session WebSocket会话
     * @param patientId 患者ID，从路径参数中获取
     */
    @OnMessage
    public void onMessage(String message, Session session, @PathParam("patientId") String patientId) {
        log.info("服务端收到患者patientId={}的消息:{}", patientId, message);
        // 解析消息内容
        JSONObject obj = JSONUtil.parseObj(message);
        String toDoctorId = obj.getStr("to"); // 发送给哪个医生
        String text = obj.getStr("text"); // 发送的消息文本
        // 查找接收消息的医生的WebSocket会话并发送消息
        Session toSession = sessionMap.get(toDoctorId);
        if (toSession != null) {
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("from", patientId);
            jsonObject.put("text", text);
            this.sendMessage(jsonObject.toString(), toSession);
            log.info("发送给医生doctorId={}，消息：{}", toDoctorId, jsonObject.toString());
        } else {
            log.info("发送失败，未找到医生doctorId={}的session", toDoctorId);
        }
    }

    /**
     * WebSocket通信发生错误时调用
     * @param session WebSocket会话
     * @param error 错误异常
     */
    @OnError
    public void onError(Session session, Throwable error) {
        log.error("发生错误");
        error.printStackTrace();
    }

    /**
     * 发送消息给指定的WebSocket会话
     * @param message 要发送的消息内容
     * @param toSession 接收消息的WebSocket会话
     */
    private void sendMessage(String message, Session toSession) {
        try {
            log.info("服务端给客户端[{}]发送消息{}", toSession.getId(), message);
            toSession.getBasicRemote().sendText(message);
        } catch (IOException e) {
            log.error("服务端发送消息给客户端失败", e);
        }
    }

    /**
     * 向所有在线客户端广播消息
     * @param message 要广播的消息内容
     */
    private void sendAllMessage(String message) {
        try {
            for (Session session : sessionMap.values()) {
                log.info("服务端给客户端[{}]发送消息{}", session.getId(), message);
                session.getBasicRemote().sendText(message);
            }
        } catch (IOException e) {
            log.error("服务端发送消息给客户端失败", e);
        }
    }
}
